import { Subject, Observable } from 'rxjs';
import { IBzCalendarLayoutConfig } from '../interface/ibz-calendar-layout-config';
import { IBzCalendarConfig } from '../interface/ibz-calendar-config';
import { CalendarDomUtil } from '../utils/calendar-dom-util';
import { IBzCalendarWeekNode } from '../interface/ibz-calendar-week-node';
import { CalendarEvent } from '../calendar-global';
import { Moment } from 'moment';

/**
 * 日历控制器
 *
 * @export
 * @class IBzCalendarController
 */
export class IBzCalendarController {
    /**
     * 事件组
     *
     * @private
     * @type {*}
     * @memberof IBizObject
     */
    private events: Map<string, any> = new Map();

    /**
     * 日历实例
     *
     * @protected
     * @type {*}
     * @memberof IBzCalendarController
     */
    protected calendar: any;

    /**
     * 时间格式化，必须包含日期和时间
     *
     * @type {string}
     * @memberof IBzCalendarController
     */
    public readonly dateFormat: string = 'YYYY:MM:DD HH:mm:ss';

    /**
     * 数据变更流
     *
     * @protected
     * @type {Subject<any[]>}
     * @memberof IBzCalendarController
     */
    protected changeSubject: Subject<any[]> = new Subject();

    /**
     * Dom操作工具类
     *
     * @type {CalendarDomUtil}
     * @memberof IBzCalendarController
     */
    public util: CalendarDomUtil = new CalendarDomUtil();

    /**
     * 参数
     *
     * @type {IBzCalendarConfig}
     * @memberof IBzCalendarController
     */
    public option: IBzCalendarConfig;

    /**
     * 布局配置
     *
     * @type {IBzCalendarLayoutConfig}
     * @memberof IBzCalendarController
     */
    public layoutConfig: IBzCalendarLayoutConfig = { };

    /**
     * 当前日历数据
     *
     * @type {any[]}
     * @memberof IBzCalendarController
     */
    public items: any[] = [];

    /**
     * 当前选中节点
     *
     * @type {IBzCalendarWeekNode}
     * @memberof IBzCalendarController
     */
    public selectNode: IBzCalendarWeekNode;

    /**
     * 设置参数
     *
     * @param {IBzCalendarConfig} opt
     * @memberof IBzCalendarController
     */
    public setOption(opt: IBzCalendarConfig): void {
        this.option = this.initOption(opt);
        this.fire(CalendarEvent.OptionChange, this.option);
    }

    /**
     * 初始化配置
     *
     * @protected
     * @param {IBzCalendarConfig} opt
     * @returns {IBzCalendarConfig}
     * @memberof IBzCalendarController
     */
    protected initOption(opt: IBzCalendarConfig): IBzCalendarConfig {
        const config: IBzCalendarConfig = {
            dateFormat: 'YYYY-MM-DD HH:mm:ss',
            allowTimeOverlap: opt.allowTimeOverlap || false,
            timeSplitScale: opt.timeSplitScale || 60,
            startTimeKey: opt.startTimeKey || 'startTime',
            endTimeKey: opt.endTimeKey || 'endTime',
            textKey: opt.textKey || 'text'
        };
        if (config.layoutConfig) {
            Object.assign(this.layoutConfig, config.layoutConfig);
        }
        config.layoutConfig = this.layoutConfig;
        return config;
    }

    /**
     * 设置数据集
     *
     * @param {any[]} items
     * @memberof IBzCalendarController
     */
    public setItems(items: any[]): void {
        if (items) {
            this.items.splice(0, this.items.length);
            this.items.push(...items);
            this.changeSubject.next(this.items);
        }
    }

    /**
     * 订阅数据变更流
     *
     * @returns {Observable<any[]>}
     * @memberof IBzCalendarController
     */
    public changeObservable(): Observable<any[]> {
        return this.changeSubject.asObservable();
    }
    
    /**
     * 设置日历
     *
     * @param {*} calendar
     * @memberof IBzCalendarController
     */
    public setCalendar(calendar: any): void {
        this.calendar = calendar;
    }

    /**
     * 向组件外发送数据变更事件
     *
     * @param {IBzCalendarWeekNode} item
     * @memberof IBzCalendarController
     */
    public externalItemChange(item: IBzCalendarWeekNode): void {
        this.calendar.dataChange.emit(item.data);
    }

    /**
     * 向组件外部发送项点击事件
     *
     * @param {IBzCalendarWeekNode} item
     * @memberof IBzCalendarController
     */
    public externalItemClick(item: IBzCalendarWeekNode): void {
        this.calendar.itemClick.emit(item.data);
    }

    /**
     * 向组件外部发送新建事件
     *
     * @param {*} data
     * @memberof IBzCalendarController
     */
    public externalNewItem(data: any): void {
        this.calendar.newItem.emit(data);
    }

    /**
     * 计算天标识
     *
     * @param {Moment} start
     * @param {Moment} end
     * @returns {string}
     * @memberof IBzCalendarController
     */
    public calcDayKey(start: Moment, end: Moment): string {
        return start.format(this.dateFormat) + '_' + end.format(this.dateFormat);
    }

    /**
     * 注册事件
     *
     * @param {string} eventName
     * @returns {Observable<any>}
     * @memberof IBzCalendarController
     */
    public on(eventName: string): Observable<any> {
        if (eventName && !Object.is(eventName, '')) {
            if (!this.events.get(eventName)) {
                const subject: Subject<any> = new Subject();
                this.events.set(eventName, subject);
                return subject.asObservable();
            }
            return this.events.get(eventName).asObservable();
        }
        throw new Error(`注册事件名称不能为空`);
    }

    /**
     * 发送事件
     *
     * @param {string} eventName
     * @param {*} [data]
     * @memberof IBzCalendarController
     */
    public fire(eventName: string, data?: any): void {
        const subject: Subject<any> = this.events.get(eventName);
        if (subject) {
            subject.next(data);
        }
    }

}